<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>book</title>
  <script src="./js/jquery.min.1.7.js"></script>
  <script src="./js/turn.min.js"></script>
  <script src="./js/coco-message.min.js"></script>
  <script src="./js/zoom.min.js"></script>
  <script src="./js/jquery.webui-popover.min.js"></script>
  <script src="./js/imagesloaded.pkgd.min.js"></script>
  <link rel="stylesheet" href="./css/book-style.css">
  <link rel="stylesheet" href="./css/jquery.webui-popover.min.css">
</head>
<body>
  <!-- 起始loading -->
  <div class="load-container">
    <div class="title">正在加速渲染中...</div>
    <div class="load-box">
      <div class="load load1"></div>
      <div class="load load2"></div>
      <div class="load"></div>
    </div>
  </div>
  <div class="wrap">
    <!-- 工具栏 -->
    <div class="tool-bar">
      <div class="page-title">
        xxx说明书
      </div>
      <div class="page-bar tool-list">
        <div class="button-bar first-button">
          <img src="./pics/last-button.svg">
        </div>
        <div class="button-bar left-button">
          <img src="./pics/left-button.svg">
        </div >
        <div class="pages-jumper">
          <input id="pageJump" onkeyup="this.value=this.value.replace(/[^0-9]+/,'');">
          <span id="pageTotal"> /-页</span>
          <div class="jumper-button">跳转 </div>
        </div>
        <div class="button-bar right-button">
          <img src="./pics/right-button.svg">
        </div>
        <div class="button-bar last-button">
          <img src="./pics/first-button.svg">
        </div>
      </div>
      <div class="full-bar tool-list">
        <div class="button-bar enlarge-button" data-placement="bottom-left">
          <img src="./pics/enlarge.svg">
        </div>
         <div class="button-bar reduce-button" data-placement="bottom-left">
          <img src="./pics/reduce.svg">
        </div>
        <div class="button-bar full-button" data-placement="bottom-left">
          <img src="./pics/full.svg">
        </div>
        <div class="button-bar not-full-button" data-placement="bottom-left" style="display: none;">
          <img src="./pics/not-full.svg">
        </div>
      </div>
    </div>
    <div class="main">
      <!-- 目录列表 -->
      <div class="catalogue-container"></div>
      <!-- book -->
      <div class="flipBook-container">
        <div class="flipBook-pages">
            <!-- 左翻页 -->
          <div class="flip-button flip-button-left">
            <img src="./pics/previous-normal.png" >
          </div>
          <!-- 翻书组件 -->
          <div class="flipBook-book"></div>
          <!-- 右翻页 -->
          <div class="flip-button flip-button-right">
            <img src="./pics/next-normal.png" >
          </div>
        </div>
        <div class="footer-pages">
          <div class="pages-two">
            <div id="pageLeft">起始页</div>
            <div class="line"></div>
            <div id="pageRight">第1页</div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script type="text/javascript">
    // a4的宽/高
    const A4_SIZE = 21 / 29.7
    // 两页书的宽/高
    const BOOK_WIDTH = 42
    const BOOK_HEIGHT = 29.7
    const BOOK_SIZE = BOOK_WIDTH / BOOK_HEIGHT

    // 对n页（2n图片）懒加载
    const LAZY_PAGES = 2

    let totalPage = 0, coverImg, directoryList = [], title = ''

    // 弹出层设置
    const getPopSettings = (content) => ({
      trigger: 'hover',
      width: 100,
      title: '',
      content,
      multi: true,
      closeable: false,
      style: 'inverse',
    })

    // 监听消息
    window.addEventListener("message", (message)=>{
      const {mode, data} =JSON.parse(message.data) || {}
      if(!data || !mode) return
      switch(mode) {
        case 'increment' :incrementRenderBook(data);
        case 'catalogue': createCatalogue(data)
        case 'img': addLazyImage(data)
        case 'fullScreen': handleFullScreen(data)
      }
    })


    // 监听屏幕宽高变化
    window.addEventListener('resize', () => {
      updateLayout()
    })

    // 悬浮目录
    function updateCatalogueLayout() {
      const windowWidth = $(window).width()
      const parentNode = $('.wrap')
      if(windowWidth <= 1280) {
        parentNode.addClass('un-flod')
        parentNode.addClass('hover')
      } else {
        parentNode.removeClass('hover')
        parentNode.removeClass('un-flod')
      }
    }

    // 更新盒子宽高布局
    function updateLayout() {
      const wrapEle = $('.wrap')
      const flipBookContainer = $('.flipBook-container')
      const containerHeight = flipBookContainer.height()
      const flipBook = $('#flipBook')
      let flipBookWidth = BOOK_SIZE * containerHeight
      let flipBookHeight= containerHeight
      const windowHeight = $(window).height()
      const windowWidth = $(window).width()
      wrapEle.removeClass('lower')
      if(windowWidth / windowHeight < BOOK_SIZE) {
        flipBookWidth = windowWidth - 160
        flipBookHeight = flipBookWidth / BOOK_SIZE
        wrapEle.addClass('lower')
      }
      flipBook.css({height: flipBookHeight, width: flipBookWidth })
      setTimeout(() => {
        flipBook.turn("size", flipBookWidth, flipBookHeight);
      })
      const pageWrappers = $('.page-wrapper')
      pageWrappers?.css({height: flipBookHeight, width: A4_SIZE * flipBookHeight })
      updateCatalogueLayout()
    }

    // 创建flipbook父盒子
    function createFlipBook() {
      $('#flipBook').remove()
      const boxEl = $('<div id="flipBook"></div>')
      $('.flipBook-book').append(boxEl)
      addEventPreAndNext('.left-button', '.right-button')
      addEventPreAndNext('.flip-button-left', '.flip-button-right')
      addEventFirstAndLast()
      addEventPageJump()
      addEventEnlargeAndReduce()
      addEventFullScreen()
      updateLayout()
      $('#pageTotal').text(`/${totalPage}页`)
    }

    // 绑定pre-next左右翻页按钮事件
    function addEventPreAndNext(leftEle, rightEle) {
      const flipBook = $('#flipBook')
      const leftButton = $(leftEle)
      const rightButton = $(rightEle)
      if(leftButton.length) {
        if(leftEle === '.left-button') leftButton.webuiPopover('destroy').webuiPopover(getPopSettings('上一页'));
        leftButton.off( "click", "**" )
        leftButton.on('click', () => {
          const currentPage = flipBook.turn('page')
          if(currentPage === 1 || currentPage === 0) {
            return cocoMessage.warning("这是第一页。", 1000)
          }
          handleTurnPage(currentPage - 2)
        })
      }
      if(rightButton.length) {
        if(rightEle === '.right-button') rightButton.webuiPopover('destroy').webuiPopover(getPopSettings('下一页'));
        rightButton.off( "click", "**" )
        rightButton.on('click', () => {
          const currentPage = flipBook.turn('page')
          if(currentPage === totalPage || totalPage % 2 !== 0 && currentPage === totalPage - 1) {
            return cocoMessage.warning("这是最后一页。", 1000)
          }
          handleTurnPage(currentPage + 2)
        })
      }
    }

    // 绑定跳转事件
    function addEventPageJump(jumpEle = '.jumper-button', inputEl = '#pageJump') {
      const flipBook = $('#flipBook')
      const pageJumpButton= $(jumpEle)
      const pageJumpInput= $(inputEl)
      const handler = () => {
        const inputVal = pageJumpInput.val()
        const pth = !!inputVal && Number(inputVal)
        if(!pth && pth !== 0) cocoMessage.warning("请输入正确的页码！", 1000)
        else handleTurnPage(pth)
      }
      if(pageJumpButton.length) {
        pageJumpButton.off( "click", "**" )
        pageJumpButton.on('click', handler)
      }
      if(pageJumpInput.length) {
        pageJumpInput.off( "keydown", "**" )
        pageJumpInput.on('keydown', (event) => {
          if(event.keyCode === 13) handler()
        })
      }
    }

    // 绑定前进至第一页与最后一页按钮事件
    function addEventFirstAndLast(firstEle = '.first-button', lastEle = '.last-button') {
      const flipBook = $('#flipBook')
      const firstButton = $(firstEle)
      const lastButton = $(lastEle)
      if(firstButton.length) {
        firstButton.webuiPopover('destroy').webuiPopover(getPopSettings('第一页'));
        firstButton.off( "click", "**" )
        firstButton.on('click', () => {
          handleTurnPage(1)
        })
      }
      if(lastButton.length) {
        lastButton.webuiPopover('destroy').webuiPopover(getPopSettings('最后一页'));
        lastButton.off( "click", "**" )
        lastButton.on('click', () => {
          handleTurnPage(totalPage)
        })
      }
    }

    // 绑定放大与缩小按钮事件
    function addEventEnlargeAndReduce(enlargeEle = '.enlarge-button', reduceEle = '.reduce-button') {
      const flipBook = $('#flipBook')
      const enlargeButton = $(enlargeEle)
      const reduceButton = $(reduceEle)
      if(enlargeButton.length) {
        enlargeButton.webuiPopover('destroy').webuiPopover(getPopSettings('放大'));
        enlargeButton.off( "click", "**" )
        enlargeButton.on('click', () => {
          zoomIn()
        })
      }
      if(reduceButton.length) {
        reduceButton.webuiPopover('destroy').webuiPopover(getPopSettings('缩小'));
        reduceButton.off( "click", "**" )
        reduceButton.on('click', () => {
          zoomOut()
        })
      }
    }

    // 全屏处理
    function handleFullScreen({ isFullscreen }) {
      const fullButton = $('.full-button')
      const notFullEle = $('.not-full-button')
      const notFullButton = $(notFullEle)
      $('.webui-popover').css({display: 'none'})
      if(isFullscreen) {
        $('.wrap').addClass('full-screen')
      } else {
        $('.wrap').removeClass('full-screen')
        const zooming = isZooming()
        zooming && zoomOut()
        setTimeout(() => {
          updateLayout()
        }, 800)
      }
    }

    // 绑定全屏事件
    function addEventFullScreen(fullEle = '.full-button', notFullEle = '.not-full-button') {
      const fullButton = $(fullEle)
      const notFullButton = $(notFullEle)
      if(fullButton.length) {
        fullButton.webuiPopover('destroy').webuiPopover(getPopSettings('全屏'));
        fullButton.off( "click", "**" )
        fullButton.on('click', () => {
          const zooming = isZooming()
          zooming && zoomOut()
          setTimeout(() => {
            window.parent.postMessage(JSON.stringify({
              mode: 'full'
            }))
          }, zooming ? 500: 0)
        })
      }
      if(notFullButton.length) {
        notFullButton.webuiPopover('destroy').webuiPopover(getPopSettings('取消全屏'));
        notFullButton.off( "click", "**" )
        notFullButton.on('click', () => {
          const zooming = isZooming()
          zooming && zoomOut()
          setTimeout(() => {
            window.parent.postMessage(JSON.stringify({
              mode: 'not-full'
            }))
          }, zooming ? 500: 0)
        })
      }
    }

    // 创建目录盒子
    function createCatalogueEle() {
      // 工具栏
      $('.page-title').text(title)
      $('#pageJump').val(1)

      const createLiEle = (directory) => {
        return `<li data-page="${directory.pth}"><div class="prefix-title">${directory.title}</div></li>`
      }
      const html = `
        <div class="catalogue-header">
          <p class="catalogue-title">目录</p>
        </div>
        <div class="catalogue-box">
          <ul class="catalogue-list">
            ${directoryList.map(directory => createLiEle(directory)).join('')}
          </ul>
        </div>
        <div class="catalogue-flod" data-placement="right" ><img class="flod-svg" src="./pics/left-one.svg"></img></div>
        `
      const parentNode = $('.catalogue-container')
      parentNode.append($(html))
      $('.catalogue-list').on('click', 'li',(event) => {
        const goPage = $(event.currentTarget).data('page')
        if(goPage) handleTurnPage(goPage)
      })
      $('.catalogue-flod').on('click', () => {
        if($('.wrap').hasClass('un-flod')) {
          $('.wrap').removeClass('un-flod')
        } else {
          $('.wrap').addClass('un-flod')
        }
      })
    }

    // 创建目录
    function createCatalogue(data = {}) {
      totalPage = data.totalPage
      coverImg = data.coverImg
      directoryList = data.directoryList
      title = data.title
      createCatalogueEle()
      incrementRenderBook()
    }

    // 判断当前pth是否已经存在
    function isPthExist(pth) {
      return $('#flipBook').turn("hasPage", pth)
    }

    // 设置图片load监听
    function addEventImageLoad(pth) {
      const imgNode = $(`#pageImg${pth}`)
      imagesLoaded(`#pageImg${pth}`, () => {
        if(imgNode.prev('.before-load-container').length) {
          imgNode.prev('.before-load-container').remove()
          imgNode.css({opacity: 1})
        }
      })
    }

    // 创建图片父盒子-懒加载
    function createLazyImageEle(pth) {
      const parentNode = $(`<div  id="pageMark${pth}" class="page-mark " data-page="${pth}">`)
      const loadingNode = $(`<div class="before-load-container"><div class="before-load"/></div>`)
      const gradientNode = $(`<div class="gradient"></div>`)
      parentNode.append(gradientNode)
      parentNode.append(loadingNode)
      return parentNode
    }

    // 增加图片盒子-懒加载
    function addLazyImage({parentNode, pth, src}) {
      if(!src) return
      const parentEle = parentNode ?? $(`#pageMark${pth}`)
      if(!parentEle.length || parentEle.find('img').length) return
      const imgNode = $(`<img id="pageImg${pth}" class="page-img" style="width:100%;height:100%;opacity:0" src="${src}" />`)
      parentEle.append(imgNode)
      addEventImageLoad(pth)
      return parentEle
    }

    // 直接生成图片盒子
    function createImageEle(pth, src) {
      return addLazyImage({parentNode: createLazyImageEle(pth), pth, src})
    }

    // 返回相邻两页
    function getTowBrotherPth(pth) {
      let pages = []
      if(pth % 2) {
        pages.push(pth, pth - 1)
      } else {
        pth === totalPage ? pages.push(pth) : pages.push(pth, pth + 1)
      }
      return pages.sort((a, b) => a - b)
    }

    // 返回从first开始的n位数数组
    function createPthArray(first, n) {
      const array = []
      for (let index = 0; index < n; index++) {
        array.push(first + index)
      }
      return array
    }

    // 获取相邻图片
    function getBrotherImgPth() {
      const currentPage = $("#flipBook").turn("page")
      const imgPth = new Set([currentPage])
      const addPth = (arg) => {
        arg.forEach(data => imgPth.add(data))
      }
      if(currentPage === 1 ) {
        addPth(createPthArray(2, LAZY_PAGES * 2))
      } else if(currentPage === totalPage) {
        addPth(createPthArray(totalPage - LAZY_PAGES * 2, LAZY_PAGES * 2))
      } else {
        if(currentPage % 2) {
          addPth([...createPthArray(currentPage - LAZY_PAGES * 2 - 1, 2 * LAZY_PAGES + 1), ...createPthArray(currentPage + 1, LAZY_PAGES * 2)])
        } else {
          addPth([...createPthArray(currentPage - LAZY_PAGES * 2, 2 * LAZY_PAGES ),...createPthArray(currentPage + 1, 2 * LAZY_PAGES + 1)])
        }
      }
      return Array.from(imgPth).filter(pth => pth >= 1 && pth <= totalPage)
    }

    // 获取需要懒加载的相邻图片
    function getLazyImgPth() {
      return getBrotherImgPth().filter(pth => !isPthExist(pth))
    }

    // 检查当前页是否加载完毕
    function checkCurrentPth(page) {
      const pages = getTowBrotherPth(page)
      pages.forEach(pth => {
        addEventImageLoad(pth)
      })
    }

    // 更新页码
    function updateFooterPage(page) {
      const pages = getTowBrotherPth(page)
      $('#pageLeft').text(pages[0] === 0 ? '起始页': `第${pages[0]}页`)
      $('#pageRight').text(pages.length !== 2 ? '末尾页':`第${pages[1]}页`)
    }

    function onTurning(event, page, view) {
      updateFooterPage(page)
    }

    // 翻页完成事件
    function onTurned(event, page, view) {
      checkCurrentPth(page)
      // 获取懒加载pth
      const lazyImgPth = getLazyImgPth()

      if(lazyImgPth.length) {
        // 创建懒加载盒子
        lazyImgPth.forEach(pth => {
          $("#flipBook").turn('addPage',createLazyImageEle(pth), pth)
        })
        // 请求懒加载图片
        window.parent.postMessage(JSON.stringify({
          mode: 'img',
          data: {
            imgPths: lazyImgPth
          }
        }))
      }
    }

    // 翻页操作
    function handleTurnPage(pth) {
      if(!pth && pth !== 0) return
      const flipBook = $('#flipBook')
      if(flipBook.turn("page") === pth) return
      if(pth > totalPage) pth = totalPage
      else if(pth < 1) pth = 1
      if(isPthExist(pth)) {
        flipBook.turn('page', pth)
      } else {
        const pages = getTowBrotherPth(pth)
        pages.forEach(pth => flipBook.turn('addPage',createLazyImageEle(pth), pth))
        flipBook.turn('page', pth)
        window.parent.postMessage(JSON.stringify({
          mode: 'img',
          data: {
            imgPths: pages
          }
        }))
      }
      $('#pageJump').val(pth)
    }

    // 初始化zoom-放大缩小功能
    function initZoom() {
      const wrapEle = $('.wrap')
      if(!wrapEle.zoom) return
      wrapEle.zoom({
        flipbook: $('#flipBook')
      })
      wrapEle.bind('zoom.doubleTap', zoomTo);
    }

    function zoomTo() {
      const wrapEle = $('.wrap')
      setTimeout(() => {
        if (wrapEle.data().regionClicked) {
          wrapEle.data().regionClicked = false;
        } else {
          if (wrapEle.zoom('value') === 1) {
            zoomIn()
          } else {
            zoomOut()
          }
        }
      }, 100);
    }

    function zoomIn() {
      const wrapEle = $('.wrap')
      wrapEle.zoom('zoomIn');
      wrapEle.css({cursor: 'pointer'})
      wrapEle.addClass('enlarge-screen')
    }

    function zoomOut() {
      const wrapEle = $('.wrap')
      wrapEle.zoom('zoomOut');
      wrapEle.css({cursor: 'default'})
      wrapEle.removeClass('enlarge-screen')
    }

    function isZooming() {
      return $('.wrap').zoom('value') !== 1
    }

    // 增量渲染
    function incrementRenderBook() {
      createFlipBook()
      $("#flipBook").append(createImageEle(1, coverImg)).turn({
        acceleration: true, //硬件加速, 默认true, 如果是触摸设备设置为true
        autoCenter: false,  //自动居中, 默认false
        display: 'double',  //单页显示/双页显示  single/double
        gradients: true,    //翻页时的阴影渐变, 默认true
        elevation: 50,     // 翻转角度
        inclination: 0,
        page: 1,            //设置当前显示第几页
        pages: totalPage,         //总页数
        pagesInDOM: 2 + 4 * LAZY_PAGES,    // 缓存的最大页数
        when: { //监听事件
          turned: onTurned,
          turning: onTurning
        }
      })
      // 关闭初始loading
      $('.load-container').css({display: 'none'})
      // 初始化zoom
      initZoom()
    }

  </script>
</body>
</html>
